#include "mysql_prepared_statement.h"
#include "../common_define.h"

namespace sql
{


	struct BufferSizePair
	{
		char* first;
		uint32_t second;

		BufferSizePair( char* f, uint32_t s ) : first( f ), second( s ) { }
	};

	PreparedStatement::PreparedStatement( MYSQL_STMT* stmt, sql::Connection* mysql_handle )
		: mMysqlConnection( NULL ), mStmt( NULL )
	{
		mStmt = stmt;
		mMysqlConnection = mysql_handle;

		for ( unsigned int i = 0; i < ARRAY_CNT( mIsDelete ); ++i )
		{
			mBind[ i ].is_null_value = 1;
			mIsDelete[ i ] = false;
		}

		//	printf( "this %p, stmt %p, conn %p\n", this, mStmt, mMysqlConnection );
	}

	void PreparedStatement::close( )
	{
		for ( unsigned int i = 0; i < ARRAY_CNT( mBind ); ++i )
		{
			if ( mIsDelete[ i ] == false ) continue;
			if ( mBind[ i ].buffer != NULL )
			{
				//			printf( "delete char %p\n", mBind[ i ].buffer );
				delete[]( char* )mBind[ i ].buffer;
				mBind[ i ].buffer = NULL;
			}
			if ( mBind[ i ].length != NULL )
			{
				//			printf( "delete length %p\n", mBind[ i ].length );
				delete ( char* )mBind[ i ].length;
				mBind[ i ].length = NULL;
			}
			mIsDelete[ i ] = false;
		}

		if ( mStmt != NULL ) mysql_stmt_close( mStmt );

		mStmt = NULL;
		mMysqlConnection = NULL;
	}

	sql::BufferSizePair allocate_buffer_for_type( enum_field_types t )
	{
		switch ( t )
		{
		case MYSQL_TYPE_LONG:
		{
			return BufferSizePair( new char[ 4 ], 4 );
		}
		case MYSQL_TYPE_STRING: return BufferSizePair( NULL, 0 );
		default: return BufferSizePair( NULL, 0 );
		}
	}

	void PreparedStatement::setInt( unsigned int parameterIndex, int32_t value )
	{
		if ( parameterIndex >= getStmtParameMaxCount( ) ) return;

		enum_field_types t = MYSQL_TYPE_LONG;

		BufferSizePair p = allocate_buffer_for_type( t );

		parameterIndex--;

		MYSQL_BIND * param = &mBind[ parameterIndex ];


		param->buffer_type = t;

		if ( mIsDelete[ parameterIndex ] == true )
		{
			if ( param->buffer != NULL ) delete[] static_cast< char * >( param->buffer );
			if ( param->length != NULL )
			{
				delete param->length;
				param->length = NULL;
			}
		}
		mIsDelete[ parameterIndex ] = true;

		param->buffer_type = t;
		//	if( param->buffer != NULL ) delete [] static_cast<char *>(param->buffer);
		param->buffer = p.first;
		param->buffer_length = 0;
		param->is_null_value = 0;
		param->is_null = NULL;
		param->length = NULL;
		//	if( param->length != NULL )
		//	{
		//	    delete param->length;
		  //  	param->length       = NULL;
		//	}

		memcpy( param->buffer, &value, p.second );
	}

	void PreparedStatement::setUInt( unsigned int parameterIndex, uint32_t value )
	{
		if ( parameterIndex == 0 || parameterIndex >= getStmtParameMaxCount( ) ) return;

		enum_field_types t = MYSQL_TYPE_LONG;

		BufferSizePair p = allocate_buffer_for_type( t );

		parameterIndex--;

		MYSQL_BIND * param = &mBind[ parameterIndex ];

		if ( mIsDelete[ parameterIndex ] == true )
		{
			if ( param->buffer != NULL )
			{
				delete[] static_cast< char * >( param->buffer );
				param->buffer = NULL;
			}
			if ( param->length != NULL )
			{
				delete ( char* )param->length;
				param->length = NULL;
			}
		}

		mIsDelete[ parameterIndex ] = true;

		param->buffer_type = t;
		//	if( param->buffer != NULL ) delete [] static_cast<char *>(param->buffer);
		param->buffer = p.first;
		param->buffer_length = 0;
		param->is_null_value = 0;
		param->is_null = NULL;
		param->length = NULL;
		//	if( param->length != NULL )
		//	{
		//		delete param->length;
		//    	param->length       = NULL;
		//	}

		memcpy( param->buffer, &value, p.second );

	}

	void PreparedStatement::setString( unsigned int parameterIndex, const char* value )
	{
		if ( parameterIndex == 0 || parameterIndex >= getStmtParameMaxCount( ) ) return;

		if ( value == NULL ) return;

		uint32_t value_length = strlen( value );

		if ( value_length > 256 * 1024 ) return;

		--parameterIndex; /* DBC counts from 1 */

		enum_field_types t = MYSQL_TYPE_STRING;

		MYSQL_BIND * param = &mBind[ parameterIndex ];

		if ( mIsDelete[ parameterIndex ] == true )
		{
			if ( param->buffer != NULL )
			{
				delete[] static_cast< char * >( param->buffer );
				param->buffer = NULL;
			}
			if ( param->length != NULL )
			{
				delete ( char* )param->length;
				param->length = NULL;
			}
		}


		mIsDelete[ parameterIndex ] = true;

		//	if( param->buffer != NULL ) delete [] static_cast<char *>(param->buffer);

		param->buffer_type = t;
		param->buffer = memcpy( new char[ value_length + 1 ], value, value_length + 1 );
		param->buffer_length = value_length + 1;
		param->is_null_value = 0;
		param->is_null = NULL;

		//    delete param->length;
		param->length = new unsigned long( static_cast< unsigned long >( value_length ) );
	}

	uint32_t PreparedStatement::executeUpdate( )
	{
		my_bool rtn = mysql_stmt_bind_param( mStmt, mBind );
		if ( rtn != 0 ) return 0;

		int execut = mysql_stmt_execute( mStmt );
		if ( execut != 0 ) return 0;

		return mysql_stmt_affected_rows( mStmt );
	}

	void PreparedStatement::setBlob( unsigned int parameterIndex, const char* value, uint32_t length )
	{
		if ( parameterIndex == 0 || parameterIndex >= getStmtParameMaxCount( ) ) return;

		if ( value == NULL ) return;

		uint32_t value_length = length;

		if ( value_length > 256 * 1024 ) return;

		--parameterIndex; /* DBC counts from 1 */

		enum_field_types t = MYSQL_TYPE_BLOB;

		MYSQL_BIND * param = &mBind[ parameterIndex ];

		if ( mIsDelete[ parameterIndex ] == true )
		{
			if ( param->buffer != NULL )
			{
				delete[] static_cast< char * >( param->buffer );
				param->buffer = NULL;
			}
			if ( param->length != NULL )
			{
				delete ( char* )param->length;
				param->length = NULL;
			}
		}


		mIsDelete[ parameterIndex ] = true;

		//	if( param->buffer != NULL ) delete [] static_cast<char *>(param->buffer);


		param->buffer_type = t;
		param->buffer = memcpy( new char[ value_length ], value, value_length );
		param->buffer_length = value_length;
		param->is_null_value = 0;
		param->is_null = NULL;

		//    delete param->length;
		param->length = new unsigned long( static_cast< unsigned long >( value_length ) );

	}

}


